#!/bin/sh
# Copyright (c) Huawei Technologies Co., Ltd. 2012-2023. All rights reserved.
# Description: it's a description sample.
#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

SYS_NAME=`uname -s`
if [ "${SYS_NAME}" = "SunOS" ]; then
    MYAWK="nawk"
else
    MYAWK="awk"
fi

RETURN_INVALID=1
ERROR_CHECK_ORACLE_INSTALL_TYPE=81
ERROR_ORACLE_AUTH_INFO_FAILED=19
SCRIPT_LOG_PATH="$DATA_BACKUP_AGENT_HOME/DataBackup/ProtectClient/ProtectClient-E/slog/Plugins/GeneralDBPlugin"
AGENT_ROOT_PATH="$DATA_BACKUP_AGENT_HOME/DataBackup/ProtectClient/ProtectClient-E"

TMP_PATH="${AGENT_ROOT_PATH}/tmp"
STMP_PATH="${AGENT_ROOT_PATH}/stmp"

TIME_FORMAT="'YYYY-MM-DD_HH24:MI:SS'"

RESULT_TMP_FILE_PREFIX="result_tmp"
RESULT_FILE="${STMP_PATH}/${RESULT_TMP_FILE_PREFIX}${PID}"

MONITOR_NAME="procmonitor.sh"
MONITOR_FILENAME="${SCRIPT_ROOT_PATH}/${MONITOR_NAME}"

# LOG GROLAB VAR
LOG_FILE_NAME="${SCRIPT_LOG_PATH}/oracle_script.log"
LOG_FILE_COMPRESS_SUFFIX="gz"
MAX_LOG_FILE_COUNT=5
MAX_NUM_COMPRESS_LOGNAME="${LOG_FILE_NAME}.${MAX_LOG_FILE_COUNT}.${LOG_FILE_COMPRESS_SUFFIX}"
MAX_LOG_SIZE_BYTE=52428800
SHELL_TYPE_SH="/bin/sh"
EXPORT_ENV="if [ -f ~/.profile ]; then . ~/.profile; fi;"


log()
{
    if [ -z "${LOG_FILE_NAME}" ]; then
        echo "Error log file is none"
        return ${RETURN_INVALID}
    fi
    if [ ! -f "${LOG_FILE_NAME}" ]; then
        touch "${LOG_FILE_NAME}"
        chmod 600 "${LOG_FILE_NAME}" 
    fi
    
    LOG_DATE=`date +%y-%m-%d--%H:%M:%S`
    if [ "SunOS" = "${SYS_NAME}" ]; then
        command -v whoami >/dev/null
        if [ $? -eq 0 ]; then
            LOG_USER_NAME=`whoami`
        else
            LOG_USER_NAME=`/usr/ucb/whoami`
        fi
    else
        LOG_USER_NAME=`whoami`
    fi
    exec_script_file_name=`echo "$0" | $MYAWK -F "/" '{print $NF}'`
    echo "[${LOG_DATE}][${1}][${2}][$$][${LOG_USER_NAME}][${exec_script_file_name}] " >> "${LOG_FILE_NAME}"
    LOGFILESIZE=`ls -l "${LOG_FILE_NAME}" | ${MYAWK} -F " " '{print $5}'`
    if [ "${LOGFILESIZE}" -lt ${MAX_LOG_SIZE_BYTE} ]; then
        return 0
    fi
    if [ -f "${MAX_NUM_COMPRESS_LOGNAME}" ]; then
        rm -f "${MAX_NUM_COMPRESS_LOGNAME}"
    fi
    logfile_num=`expr ${MAX_LOG_FILE_COUNT} - 1`
    while [ "${logfile_num}" -ge 0 ]; do
        if [ "${logfile_num}" -eq 0 ]; then
            gzip -f -q -9 "${LOG_FILE_NAME}"
            temp_logfile_name="${LOG_FILE_NAME}.${LOG_FILE_COMPRESS_SUFFIX}"
        else
            temp_logfile_name="${LOG_FILE_NAME}.${logfile_num}.${LOG_FILE_COMPRESS_SUFFIX}"                 
        fi

        if [  -f "${temp_logfile_name}" ]; then
            dest_num=`expr "${logfile_num}" + 1`
            mv -f "${temp_logfile_name}" "${LOG_FILE_NAME}.${dest_num}.${LOG_FILE_COMPRESS_SUFFIX}" 
            chmod 440 "${LOG_FILE_NAME}.${dest_num}.${LOG_FILE_COMPRESS_SUFFIX}" 
        fi
        logfile_num=`expr "${logfile_num}" - 1`
    done
    if [ ! -f "${LOG_FILE_NAME}" ]; then
        touch "${LOG_FILE_NAME}"
        chmod 600 "${LOG_FILE_NAME}" 
    fi
}

log_error()
{
    log "ERRO" "${1}"
    return $?
}

log_info()
{
    log "INFO" "${1}"
    return $?
}

log_warn()
{
    log "WARN" "${1}"
    return $?
}

log_debug()
{
    log "DBUG" "${1}"
    return $?
}

delete_file()
{
    if [ $# -lt 1 ]; then
        return ${RETURN_INVALID}
    fi
    last_index=$#
    # 取最后一个入参判断是否要将删除的临时文件内容输出到日志中
    output_file_content_flag="$(echo "$@" | awk '{print $NF}')"
    for i in "$@"; do
        if [ ! -f "${i}" ]; then
            continue
        fi
        if [ "$output_file_content_flag" = "true" ]; then
             if [ "${SYS_NAME}" != "AIX" ]; then
                log_info "file ${i} content is:`cat ${i}`"
            else
                log_info "file ${i} content is:`tail -n 100 ${i}`"
            fi
        fi
        rm -fr "${i}" >> ${LOG_FILE_NAME} 2>&1
        if [ $? -ne 0 ]; then
            log_error "Delete file (${i}) failed"
            return ${RETURN_INVALID}
        fi
    done
}

rd_substr()
{
    begin_index=$2
    substr_len=$3
    if [ $# -eq 2 ]; then
        echo "$1" | ${MYAWK} -v begin="${begin_index}" '{print substr($1, begin)}'
    elif [ $# -eq 3 ]; then
        echo "$1" | ${MYAWK} -v begin="${begin_index}" -v ln="${substr_len}" '{print substr($1,begin,ln)}'
    fi
    return ${?}
}

get_user_shell_type()
{
    user_name=$1
    user_sell_type=
    if [ -z "${user_name}" ]; then
        log_error "Get user shell type failed user name is none"
        return ${ERROR_PARAM_INVALID}
    fi
    user_sell_type=`cat /etc/passwd | grep "^${user_name}:" | $MYAWK -F "/" '{print $NF}'`
    if [ -z "${user_sell_type}" ]; then
        log_error "Get user: [${user_name}] shell type failed"
        return ${ERROR_PARAM_INVALID}
    fi
    log_info "Get user: [${user_name}] type: [${user_sell_type}] info success"
    echo "${user_sell_type}"
}

get_user_env_file()
{
    user_name=$1
    if [ -z "${user_name}" ]; then
        log_error "User name is none can not get user env file info "
        return ${ERROR_PARAM_INVALID}
    fi
    shell_type=`get_user_shell_type "${user_name}"`
    ret_code=$?
    if [ $ret_code -ne 0 ]; then
        log_error "Get oracle shell type failed"
        return $ret_code
    fi
    if [ -z "${shell_type}" ]; then
        log_error "Get user: ${user_name} shell type failed"
        return ${RETURN_INVALID}
    fi
    if [ "${shell_type}" = "ksh" ]; then
        user_env_file=".kshrc .profile"
    elif [ "${shell_type}" = "csh" ]; then
        user_env_file=".cshrc .login .tcshrc"
    elif [ "${shell_type}" = "bash" ]; then
        user_env_file=".profile .bashrc .bash_login .bash_profile"
    elif [ "${shell_type}" = "zsh" ]; then
        user_env_file=".zshenv .zprofile .zshrc .zlogin"
    fi
    log_info "Get user: ${user_name} env file info success, ${user_env_file}"
    echo "${user_env_file}"
}

generate_export_cmd()
{
    env_file_list=$1
    user_type=$2
    export_cmd=""
    if [ -z "${env_file_list}" ]; then
        log_error " Env file list is none"
        return ${RETURN_INVALID}
    fi
    if [ "${user_type}" = "oracle" ]; then
        export_cmd=`generate_export_oracle_env "$env_file_list"`
    else
        export_cmd=`generate_export_grid_env "$env_file_list"`
    fi
    log_info "generate_export_cmd success, ${export_cmd}"
    echo "${export_cmd}"
}

generate_export_oracle_env()
{
    env_file_list=$1
    export_oracle_env=""
    if [ "${ORACLE_SHELLTYPE}" != "csh" ]; then
        for file_item in ${env_file_list}; do
            export_oracle_env="${export_oracle_env} if [ -f \"${file_item}\" ]; then . ~/${file_item}; fi;"
        done
        if [ -n "${ORACLE_BASE}" ]; then
            export_oracle_env="${export_oracle_env} export ORACLE_BASE=${ORACLE_BASE};"
        fi
        if [ -n "${ORACLE_HOME}" ]; then
            export_oracle_env="${export_oracle_env} export ORACLE_HOME=${ORACLE_HOME};export PATH=${ORACLE_HOME}/bin:$PATH;"
        fi
        export_oracle_env="${export_oracle_env} export NLS_LANG=American_America.US7ASCII;"
    else
        if [ -n "${ORACLE_BASE}" ]; then
            export_oracle_env="${export_oracle_env} setenv ORACLE_BASE ${ORACLE_BASE};"
        fi
        if [ -n "${ORACLE_HOME}" ]; then
            export_oracle_env="${export_oracle_env} setenv ORACLE_HOME ${ORACLE_HOME};setenv PATH ${ORACLE_HOME}/bin:$PATH;"
        fi
        export_oracle_env="${export_oracle_env} setenv NLS_LANG American_America.US7ASCII;"
    fi
    echo "${export_oracle_env}"
}

generate_export_grid_env()
{
    env_file_list=$1
    export_grid_env=""
    if [ "${GRID_SHELLTYPE}" != "csh" ]; then
        for file_item in ${env_file_list}; do
            export_grid_env="${export_grid_env} if [ -f \"${file_item}\" ]; then . ~/${file_item}; fi;"
        done
        if [ -n "${GRID_ORACLE_HOME}" ]; then
            export_grid_env="${export_grid_env} export ORACLE_HOME=${GRID_ORACLE_HOME};export PATH=${GRID_ORACLE_HOME}/bin:$PATH;"
        fi
        export_grid_env="${export_grid_env} export NLS_LANG=American_America.US7ASCII;"
    else
        if [ -n "${GRID_ORACLE_HOME}" ]; then
            export_grid_env="${export_grid_env} setenv ORACLE_HOME ${GRID_ORACLE_HOME};setenv PATH ${GRID_ORACLE_HOME}/bin:$PATH;"
        fi
        export_grid_env="${export_grid_env} setenv NLS_LANG American_America.US7ASCII;"
    fi
    echo "${export_grid_env}"
}

generate_export_oracle_sid()
{
    instance_name_sid=$1
    if [ "${ORACLE_SHELLTYPE}" = "csh" ]; then
        set_env_cmd="setenv ORACLE_SID ${instance_name_sid};"
    else
        set_env_cmd="ORACLE_SID=${instance_name_sid}; export ORACLE_SID;"
    fi
    echo "${set_env_cmd}"
}

generate_export_grid_oracle_sid()
{
    asm_instance_name_sid=$1
    if [ "${GRID_SHELLTYPE}" = "csh" ]; then
        set_env_cmd="setenv ORACLE_SID ${asm_instance_name_sid};"
    else
        set_env_cmd="ORACLE_SID=${asm_instance_name_sid}; export ORACLE_SID;"
    fi
    echo "${set_env_cmd}"
}

check_oracle_base_and_home()
{
    if [ -n "${ORACLE_BASE}" ] && [ ! -d "${ORACLE_BASE}" ]; then
        log_error "Get environment ORACLE_BASE var is not a directory."
        exit ${ERROR_ORACLE_AUTH_INFO_FAILED}
    fi
    if [ ${#ORACLE_BASE} -gt 2048 ]; then
        log_error "ORACLE_BASE length is greater than 2048."
        exit ${ERROR_ORACLE_AUTH_INFO_FAILED}
    fi
    if [ -n "${ORACLE_HOME}" ] && [ ! -d "${ORACLE_HOME}" ]; then
        log_error "Get environment ORACLE_HOME var is not a directory."
        exit ${ERROR_ORACLE_AUTH_INFO_FAILED}
    fi
    if [ ${#ORACLE_HOME} -gt 2048 ]; then
        log_error "ORACLE_HOME length is greater than 2048."
        exit ${ERROR_ORACLE_AUTH_INFO_FAILED}
    fi
}

kill_proc_monitor()
{
    my_ppid=$1
    monitor_pids=`ps -ef | grep ${MONITOR_NAME} | grep -v "grep" | $MYAWK -v ppid="${my_ppid}" '{if ($3==ppid) print $2}'`
    for pid in ${monitor_pids}; do
        kill -9 ${pid}
        log_info "kill procMonitor id=${pid}."
    done
}

exit_with_error()
{
    log_error "$1 is invalid."
    exit "$ERROR_PARAM_INVALID"
}

check_dir_rwx()
{
    check_user=$1
    if [ -z "${check_user}" ] || [ -z "$2" ]; then
        log_error "Check user is not can not check prviage"
        return "${RETURN_INVALID}"
    fi
    disk_arry=`echo "$2" | sed 's/;/ /g'`
    for check_dir in ${disk_arry}; do
        if [ "`rd_substr "${check_dir}" 1 1`" = "/" ]; then
            su - "${check_user}" -c "[ ! -z \"${check_dir}\" -a -d \"${check_dir}\" -a -r \"${check_dir}\" -a -w \"${check_dir}\" -a -x \"${check_dir}\" ] || exit 1"
            return $?
        fi
    done
}

check_ip_legality()
{
    if [ $# -ne 1 ]; then
        log_error "Param num is invalid, can not check ip"
        return ${RETURN_INVALID}
    fi

    OLDIFS="$IFS"

    if [ "${SYS_NAME}" != "AIX" ]; then
        IFS=' '
    fi
    VERIFY_IP_IPV4="^[0-9]\{1,3\}\.\([0-9]\{1,3\}\.\)\{2\}[0-9]\{1,3\}$"
    VERIFY_IP_IPV6="^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$"

    ip_list=`echo "$1" | $MYAWK '{ gsub(/;/," "); print $0 }'`
    for ip_item in $ip_list; do
        echo "$ip_item" | grep "${VERIFY_IP_IPV4}" >/dev/null 2>&1
        if [ $? -ne 0 ]; then
            echo "$ip_item" | grep -E "${VERIFY_IP_IPV6}" >/dev/null 2>&1
            if [ $? -ne 0 ]; then
                IFS="$OLDIFS"
                log_error "Ip: ${ip_item} is not invaild"
                return ${RETURN_INVALID}
            fi
            continue
        fi
    done
    IFS="$OLDIFS"
}

get_value()
{
    if [ $# -ne 2 ]; then
        log_error "Param num is invalid, can not get value"
        exit "$ERROR_SCRIPT_EXEC_FAILED"
    fi
    SPECIAL_CHARS="[\`$;|&<>\!]"
    param_content=$1
    key="$2"
    value=$(echo $param_content | python3 -c "import sys,json; print(json.loads(sys.stdin.readline()).get('${key}', ''))")
    if [ "$2" != "Password" ] && [ "$2" != "ASMPassword" ] && [ "$2" != "EncKey" ] && [ "$2" != "IpPortInfo" ]; then
        if [ "$2" = "storageIp" ] || [ "$2" = "dataOwnerIps" ] || [ "$2" = "dataOtherIps" ] || [ "$2" = "logOwnerIps" ] || [ "$2" = "logOtherIps" ]; then
            check_ip_legality "${value}"
            if [ ${?} -ne 0 ]; then
                echo "ERROR_PARAM_INVALID"
                break
            fi
        elif [ "$2" = "DataPath" ] || [ "$2" = "LogPath" ] || [ "$2" = "MetaDataPath" ]; then
            tmpValue=`echo "$value" | $MYAWK '{ gsub(/;/," "); print $0 }'`
            echo "$tmpValue" | grep "${SPECIAL_CHARS}" >/dev/null 2>&1
            if [ $? -eq 0 ]; then
                echo "ERROR_PARAM_INVALID"
                break
            fi
        else
            echo "$value" | grep "${SPECIAL_CHARS}" >/dev/null 2>&1
            if [ $? -eq 0 ]; then
                echo "ERROR_PARAM_INVALID"
                break
            fi
        fi
    fi
    echo "$value"
}

read_input_param()
{
    param_num=$1
    if [ -z "$param_num" ]; then
        log_warn "Param num is none canot get param"
        return
    fi
    if read -rs param_content; then
        log_info "Read input param seccess."
    else
        log_error "Get Param value error, param_num=${param_num}."
        return ${RETURN_INVALID}
    fi
    echo "${param_content}"
}

add_unix_timestamp()
{
    time=`echo "$1" | tr "_" " "`
    if [ "$SYS_NAME" = "Linux" ]; then
        su - rdadmin -s "$SHELL_TYPE_SH" -c "${EXPORT_ENV} ${AGENT_ROOT_PATH}/bin/agentcli UnixTimestamp \"$time\" Date2Unix"
    else
        su - rdadmin "$RDADMIN_SHELLTYPE" -c "${EXPORT_ENV} ${AGENT_ROOT_PATH}/bin/agentcli UnixTimestamp \"$time\" Date2Unix"
    fi
}

unix_timestamp_to_date()
{
    time=$1
    if [ "$SYS_NAME" = "Linux" ]; then
        su - rdadmin -s $SHELL_TYPE_SH  -c "${EXPORT_ENV}$AGENT_ROOT_PATH/bin/agentcli  UnixTimestamp \"$time\" Unix2Date"
    else
        su - rdadmin "$RDADMIN_SHELLTYPE" -c "${EXPORT_ENV}$AGENT_ROOT_PATH/bin/agentcli UnixTimestamp \"$time\" Unix2Date"
    fi
}

get_dir_file_info()
{
    filelist="$STMP_PATH/filelist${PID}"
    dir_path=$1;
    ora_user=$2;
    delete_file "$filelist"
    dir_path_length=`echo "$dir_path" | $MYAWK '{print length($0)}'`
    path_length=`expr "${dir_path_length}" + 1`
    log_info "Start get Dir $dir_path file info, ora_user is ${ora_user}."
    filesizeinfo=`su - "${ora_user}" -c "ls -R -l $dir_path" | $MYAWK '{print $1";"$NF";"$5}'`
    pathprefix=
    for file in $filesizeinfo; do
        title=`rd_substr "$file" 1 1`
        if [ "$title" = "d" ] || [ "$title" = "t" ] || [ "$title" = ";" ]; then
            continue
        fi
        if [ "$title" = "/" ]; then
            file=`echo "$file" | $MYAWK -F ";" '{print $1}'`
            filepathlength=`echo "$file" | $MYAWK '{print length($0)}'`
            filepathlength=`expr "${filepathlength}" - 1`
            pathprefix=`rd_substr "$file" 1 "$filepathlength"`
            continue
        fi
        filesize=`echo "$file" | $MYAWK -F ";" '{print $3}'`
        filename=`echo "$file" | $MYAWK -F ";" '{print $2}'`
        if [ -z "${filesize}" ] || [ -z "${filename}" ]; then
            continue
        fi
        fullfilename="${pathprefix}/$filename"
        fullfilename=`rd_substr "$fullfilename" "$path_length"`
        echo "$fullfilename;$filesize" >> "$filelist"
    done
}